package com.internetCafes.spms.web.tenant.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.internetCafes.spms.common.utils.ShiroUtils;
import com.internetCafes.spms.core.generic.GenericDao;
import com.internetCafes.spms.core.generic.GenericServiceImpl;
import com.internetCafes.spms.core.model.pageModel.DataGrid;
import com.internetCafes.spms.web.certificate.model.podo.EmployeeInfoDo;
import com.internetCafes.spms.web.certificate.model.podo.EmployeeInfoPo;
import com.internetCafes.spms.web.certificate.service.EmployeeInfoService;
import com.internetCafes.spms.web.customer.common.cont.CommonConst;
import com.internetCafes.spms.web.customer.common.util.UserInfoUtil;
import com.internetCafes.spms.web.customer.model.role.RoleDeptDataDo;
import com.internetCafes.spms.web.customer.model.role.RoleDeptDataPo;
import com.internetCafes.spms.web.customer.model.user.EntUserInfoDo;
import com.internetCafes.spms.web.customer.model.user.EntUserInfoPo;
import com.internetCafes.spms.web.customer.service.role.IRoleDeptDataAssoService;
import com.internetCafes.spms.web.customer.service.user.IEntUserInfoService;
import com.internetCafes.spms.web.sys.model.UserInfo;
import com.internetCafes.spms.web.tenant.common.TenantConst;
import com.internetCafes.spms.web.tenant.dao.TenantDeptInfoMapper;
import com.internetCafes.spms.web.tenant.dao.TenantInfoMapper;
import com.internetCafes.spms.web.tenant.model.TenantDeptInfo;
import com.internetCafes.spms.web.tenant.model.TenantInfo;
import com.internetCafes.spms.web.tenant.model.podo.TenantDeptInfoPlusDo;
import com.internetCafes.spms.web.tenant.service.ITenantDeptInfoPlusService;
import com.internetCafes.spms.web.tenant.service.TenantDeptInfoService;
import com.internetCafes.spms.web.tenant.vo.TenantDeptInfoVo;
import com.sms.common.util.hutool.core.collection.CollectionUtil;
import com.sms.common.util.hutool.core.util.ObjectUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 租户组织架构 TenantDeptInfoService 实现类
 *
 * @author Sunny
 * @email rekeeper2011@hotmail.com
 * @date 2019-10-31 18:09:54
 */
@Service("tenantDeptInfoService")
public class TenantDeptInfoServiceImpl extends GenericServiceImpl<TenantDeptInfo, Long> implements TenantDeptInfoService {

    @Autowired
    private TenantDeptInfoMapper tenantDeptInfoMapper;
    @Autowired
    private TenantInfoMapper tenantInfoMapper;
    @Autowired
    private IRoleDeptDataAssoService deptDataAssoService;
    @Autowired
    private ITenantDeptInfoPlusService deptInfoPlusService;
    @Autowired
    private IEntUserInfoService userInfoService;
    @Autowired
    private EmployeeInfoService employeeInfoService;


    @Override
    public TenantDeptInfoVo tree(Long tenantId, Integer filterFlag) {
        /*
         * 1-找到开始部门节点
         * 2-获取所有部门列表
         * 3-向下遍历
         */
        UserInfo userEntity = ShiroUtils.getUserEntity();
        String tenantName;

        // 获取公司信息
        if (ObjectUtil.isNotNull(tenantId)) {
            TenantInfo tenantInfoPo = tenantInfoMapper.selectByPrimaryKey(tenantId);
            if (ObjectUtil.isNull(tenantInfoPo)) {
                return null;
            }
            tenantName = tenantInfoPo.getTenantName();
        } else {
            tenantId = userEntity.getDeptId();
            tenantName = userEntity.getDeptName();
        }

        TenantDeptInfoVo rootDeptRes = new TenantDeptInfoVo(0L, tenantName, 0L, "");

        // 获取所有部门信息
        Map<String, Object> params = new HashMap<>();
        params.put("tenantId", tenantId);
        List<TenantDeptInfoVo> tenantDeptInfoList = tenantDeptInfoMapper.selectByParamsUnionTenant(params);

        // 获取部门人数
        Map<Long, Integer> memberCountMapByDeptId = deptInfoPlusService.countDeptMemberAmountByTenantId(tenantId);

        // 部门是否需要数据过滤
        boolean isFilter = !UserInfoUtil.entSuperAdminJudge(userEntity) && CommonConst.FlagEnum.IS.getId().equals(filterFlag);

        rootDeptRes.setAuthority(!isFilter);
        if (TenantConst.TENANT_DEPT_ROOT_PARENT_ID.equals(userEntity.getTenantDeptId())) {
            rootDeptRes.setAuthority(true);
        }
        // 根据用户信息判断是否需要进行数据过滤
        List<Long> ableDeptIdList = new ArrayList<>();
        if (!UserInfoUtil.entSuperAdminJudge(userEntity) && CommonConst.FlagEnum.IS.getId().equals(filterFlag)) {
            // 所在部门id
            ableDeptIdList.add(userEntity.getTenantDeptId());
            // 授权部门id
            List<Long> deptIdList = deptDataAssoService
                    .listPo(new RoleDeptDataDo().setUserId(userEntity.getId()))
                    .stream().map(RoleDeptDataPo::getDeptId)
                    .collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(deptIdList)) {
                ableDeptIdList.addAll(deptIdList);
            }
        }

        // 获取人员信息：
        EntUserInfoDo entUserInfoDo = new EntUserInfoDo();
        entUserInfoDo.setTenantId(tenantId);
        entUserInfoDo.setManagerFlag(CommonConst.FlagEnum.IS.getId());
        List<Long> memberIdList = userInfoService.listPoNoTenantId(entUserInfoDo)
                .stream().map(EntUserInfoPo::getUserId)
                .collect(Collectors.toList());

        List<EmployeeInfoPo> employeeList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(memberIdList)) {
            EmployeeInfoDo employeeInfoDo = new EmployeeInfoDo();
            employeeInfoDo.setTenantId(tenantId);
            employeeInfoDo.setIdList(memberIdList);
            employeeInfoDo.setOnCompanyFlag(CommonConst.FlagEnum.IS.getId());
            employeeInfoDo.setStatus(1);// 不知道涵义 暂时这么写
            employeeInfoDo.setEmployeeFlag(CommonConst.FlagEnum.IS.getId());
            employeeList = employeeInfoService.listPoNoTenantId(employeeInfoDo);
        }

        deptManagerInfo(rootDeptRes, tenantDeptInfoList, employeeList, memberCountMapByDeptId);

        return treeDeptInfo(rootDeptRes, tenantDeptInfoList, ableDeptIdList);
    }

    /**
     * 封装部门管理员列表和部门人员数量
     *
     * @param rootDeptRes        根节点信息
     * @param tenantDeptInfoList 企业部门列表
     * @param employeeList       管理人列表
     */
    private void deptManagerInfo(TenantDeptInfoVo rootDeptRes, List<TenantDeptInfoVo> tenantDeptInfoList, List<EmployeeInfoPo> employeeList, Map<Long, Integer> memberCountMapByDeptId) {

        if (CollectionUtil.isEmpty(employeeList)) {
            return;
        }
        Map<Long, List<EmployeeInfoPo>> employeeListGroupByDeptId = employeeList.stream().collect(Collectors.groupingBy(EmployeeInfoPo::getDeptId));
        // 开始节点信息
        if (employeeListGroupByDeptId.containsKey(rootDeptRes.getId())) {
            rootDeptRes.setManagerMemberList(
                    employeeListGroupByDeptId.get(rootDeptRes.getId())
                            .stream().map(po -> BeanUtil.toBean(po, TenantDeptInfoVo.ManagerMember.class))
                            .collect(Collectors.toList()));
        }
        rootDeptRes.setMemberAmount(memberCountMapByDeptId.getOrDefault(rootDeptRes.getId(), 0));
        // 其他节点信息
        for (TenantDeptInfoVo deptInfoVo : tenantDeptInfoList) {
            if (employeeListGroupByDeptId.containsKey(deptInfoVo.getId())) {
                deptInfoVo.setManagerMemberList(
                        employeeListGroupByDeptId.get(deptInfoVo.getId())
                                .stream().map(po -> BeanUtil.toBean(po, TenantDeptInfoVo.ManagerMember.class))
                                .collect(Collectors.toList()));
            }
            deptInfoVo.setMemberAmount(memberCountMapByDeptId.getOrDefault(deptInfoVo.getId(), 0));
        }
    }

    /**
     * 部门数据过滤封装
     *
     * @param startDeptRes       开始部门节点
     * @param tenantDeptInfoList 部门 信息列表
     * @param ableDeptIdList     授权部门id列表
     * @return 部门 属性列表节点
     */
    private TenantDeptInfoVo treeDeptInfo(TenantDeptInfoVo startDeptRes, List<TenantDeptInfoVo> tenantDeptInfoList, List<Long> ableDeptIdList) {

        // 获取子部门结点
        List<TenantDeptInfoVo> childrenDept = tenantDeptInfoList.stream()
                .filter(deptPo -> deptPo.getParentId().equals(startDeptRes.getId()))
                .collect(Collectors.toList());

        // 如果没有权限，不展示管理员，并且将当前部门下的人员数量置为0，确保数据的一致性
        if (!startDeptRes.isAuthority()) {
            startDeptRes.setManagerMemberList(new ArrayList<>());
            startDeptRes.setMemberAmount(0);
        }

        if (CollectionUtil.isNotEmpty(childrenDept)) {
            List<TenantDeptInfoVo> childrenRes = new ArrayList<>();
            for (TenantDeptInfoVo child : childrenDept) {
                // 1-如果父部门有查看权限，子部门依然有权利 | 2-如果授权的部门id列表中包含部门id， 子部门有权利
                child.setAuthority(startDeptRes.isAuthority() || ableDeptIdList.contains(child.getId()));
                // 2-递归获取子部门信息
                TenantDeptInfoVo childRes = treeDeptInfo(child, tenantDeptInfoList, ableDeptIdList);
                childrenRes.add(childRes);
            }
            childrenRes = childrenRes.stream().filter(res -> res.isAuthority()).collect(Collectors.toList());
            // 3-如果子部门的有查看的权限,后置将当前父部门的权限设置为有权限
            if (CollectionUtil.isNotEmpty(childrenRes)) {
                startDeptRes.setAuthority(true);
                startDeptRes.setChildren(childrenRes);
                int sum = childrenRes.stream().mapToInt(TenantDeptInfoVo::getMemberAmount).sum() + startDeptRes.getMemberAmount();
                startDeptRes.setMemberAmount(sum);
            }
        }

        return startDeptRes;
    }

    /**
     * 获取子部门信息
     *
     * @param startDeptRes       开始
     * @param tenantDeptInfoList 部门列表
     */
    private void findDeptChildren(TenantDeptInfoVo startDeptRes, List<TenantDeptInfoVo> tenantDeptInfoList) {
        List<TenantDeptInfoVo> children = tenantDeptInfoList.stream()
                .filter(deptPo -> deptPo.getParentId().equals(startDeptRes.getId()))
                .collect(Collectors.toList());
        if (CollectionUtil.isEmpty(children)) {
            return;
        }
        for (TenantDeptInfoVo child : children) {
            findDeptChildren(child, tenantDeptInfoList);
        }
        long certificateCount = children.stream().mapToLong(TenantDeptInfoVo::getCertificateCount).sum();
        startDeptRes.setCertificateCount(certificateCount);
        startDeptRes.setChildren(children);
    }

    @Override
    public List<TenantDeptInfo> allList() {
        HashMap<String, Object> params = new HashMap<>();
        params.put("tenantId", ShiroUtils.getUserEntity().getDeptId());
        // 获取部门列表
        return query(params);
    }

    @Override
    public List<TenantDeptInfo> query(Map<String, Object> params) {
        return tenantDeptInfoMapper.selectByParams(params);
    }

    @Override
    public TenantDeptInfo findById(Long id) {
        return tenantDeptInfoMapper.selectByPrimaryKey(id);
    }

    @Override
    public List<TenantDeptInfo> queryByIds(List<Long> ids) {
        Map<String, Object> params = new HashMap<>();
        params.put("ids", ids);
        return tenantDeptInfoMapper.selectByParams(params);
    }

    @Override
    public List<TenantDeptInfo> page(Map<String, Object> params, int page, int rows) {
        params.put("page", page);
        params.put("rows", rows);
        return tenantDeptInfoMapper.selectByParams(params);
    }

    @Override
    public long count(Map<String, Object> params) {
        return tenantDeptInfoMapper.countByParams(params);
    }

    @Override
    public TenantDeptInfo findFirst(Map<String, Object> params) {
        List<TenantDeptInfo> list = tenantDeptInfoMapper.selectByParams(params);
        TenantDeptInfo tenantDeptInfo = null;
        if (list != null && list.size() > 0) {
            tenantDeptInfo = list.get(0);
        }
        return tenantDeptInfo;
    }

    @Override
    public int save(TenantDeptInfo tenantDeptInfo) {
        return tenantDeptInfoMapper.insert(tenantDeptInfo);
    }

    @Override
    public int saveBatch(List<TenantDeptInfo> tenantDeptInfoList) {
        return tenantDeptInfoMapper.insertBatch(tenantDeptInfoList);
    }

    @Override
    public int saveSelective(TenantDeptInfo tenantDeptInfo) {
        return tenantDeptInfoMapper.insertSelective(tenantDeptInfo);
    }

    @Override
    public int update(TenantDeptInfo tenantDeptInfo) {
        return tenantDeptInfoMapper.updateByPrimaryKey(tenantDeptInfo);
    }

    @Override
    public int updateSelective(TenantDeptInfo tenantDeptInfo) {
        return tenantDeptInfoMapper.updateByPrimaryKeySelective(tenantDeptInfo);
    }

    @Override
    public int delete(Long id) {
        return tenantDeptInfoMapper.deleteByPrimaryKey(id);
    }

    @Override
    public int deleteBatch(List<Long> ids) {
        return tenantDeptInfoMapper.deleteBatchByPrimaryKey(ids);
    }

    @Override
    public void deleteBatch(Long[] ids) {
        if (ids != null && ids.length > 0) {
            for (Long id : ids) {
                delete(id);
            }
        }
    }

    @Override
    public GenericDao<TenantDeptInfo, Long> getDao() {
        return tenantDeptInfoMapper;
    }


    /**
     * DataGrid
     */
    @Override
    public DataGrid dataGrid(Map<String, Object> params, int pageNo, int pageSize) {
        params.put("page", (pageNo - 1 < 0 ? -1 : pageNo - 1) * pageSize);
        params.put("rows", pageSize);
        List<TenantDeptInfoVo> tenantDeptInfoList = selectByParamsUnionTenant(params);
        long count = tenantDeptInfoMapper.countByParamsUnionTenant(params);

        return new DataGrid(tenantDeptInfoList, count, pageSize, pageNo);
    }

    @Override
    public List<TenantDeptInfoVo> getChildren(Long id, List<TenantDeptInfoVo> resultList) {
        Map<String, Object> params = new HashMap<>();
        params.put("parentId", id);

        List<TenantDeptInfoVo> tenantDeptInfoVos = selectByParamsUnionTenant(params);
        resultList.addAll(tenantDeptInfoVos);
        if (tenantDeptInfoVos.size() != 0) {
            for (int i = 0; i < tenantDeptInfoVos.size(); i++) {
                TenantDeptInfoVo tenantDeptInfoVo = tenantDeptInfoVos.get(i);
                List<TenantDeptInfoVo> children = getChildren(tenantDeptInfoVo.getId(), resultList);
            }
        }
        return resultList;
    }

    @Override
    public List<TenantDeptInfoVo> selectByParamsUnionTenant(Map<String, Object> params) {
        return tenantDeptInfoMapper.selectByParamsUnionTenant(params);
    }

    /***
     * 1、循环部门列表
     * 2、根据当前部门ID,获取子部门的数据
     * 3、设置当前部门的数据
     *
     * @param vo
     * @param tenantId
     * @param tenantDeptInfoList
     */
    @Override
    public void getCertificateCount(TenantDeptInfoVo vo, Long tenantId, List<TenantDeptInfoVo> tenantDeptInfoList) {
        List<TenantDeptInfoVo> resultList = new ArrayList<>();
        for (TenantDeptInfoVo deptInfo : vo.getChildren()) {
            long childrenCertCount = getChildrenCertCount(deptInfo.getId(), tenantDeptInfoList);
            deptInfo.setCertificateCount(childrenCertCount);
            resultList.add(deptInfo);
            getCertificateCount(deptInfo, tenantId, tenantDeptInfoList);
        }
        vo.setChildren(resultList);
    }

    private long getChildrenCertCount(long deptId, List<TenantDeptInfoVo> tenantDeptInfoList) {
        Long count = 0L;
        List<TenantDeptInfoVo> children = getChildren(deptId, new ArrayList<>());
        for (int i = 0; i < children.size(); i++) {
            TenantDeptInfoVo tenantDeptInfoVo = children.get(i);
            for (int j = 0; j < tenantDeptInfoList.size(); j++) {
                TenantDeptInfoVo deptInfoVo = tenantDeptInfoList.get(j);
                if (tenantDeptInfoVo.getId().equals(deptInfoVo.getId())) {
                    count += deptInfoVo.getCertificateCount();
                }
            }
        }
        for (int j = 0; j < tenantDeptInfoList.size(); j++) {
            TenantDeptInfoVo deptInfoVo = tenantDeptInfoList.get(j);
            if (deptId == deptInfoVo.getId()) {
                count += deptInfoVo.getCertificateCount();
            }
        }
        return count;
    }

    @Override
    public List<TenantDeptInfoVo> countByParamsUnionEmployee(long id) {
        return tenantDeptInfoMapper.countByParamsUnionEmployee(id);
    }

    @Override
    public List<TenantDeptInfoVo> selectByParamsUnionCertificate() {
        return tenantDeptInfoMapper.selectByParamsUnionCertificate();
    }

}
